Une des applications les plus complètes à développer:

  - entrées-sorties (charger configuration, envoyer fichier)
  - informations sur les fichiers (taille, mime, date de modification)
  - lister contenu d'un dossier
  - fork (pour lancer un CGI)
  - obtenir heure courante du système
  - sockets, en mode avancé: socket multiclients
  - conformation à un protocole
  - traitement de chaîne de caractères (parser la requête)

Ici minimaliste, pour ne pas dire en chantier.

/*
  Programme   : Serveur HTTP
  Compilation : c httpBX httpBX.c -L../../lib -lservLib
  Auteur      : Masta
  Date        : 2006
*/

#include "../../include/servLib.h"
#include <sys/sendfile.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

/*==============================================================================
  Point d' entrée. 
==============================================================================*/
int main()
{
  // Parse la configuration
  // www folder ?

  // lister les dossiers, ou 403?

  // index par défaut? index.htm, index.html, index.php...

  // activer server signature ?

  //Lance le serveur sur le port TCP 80, pour 32 clients maximum.
  cbx_Serveur_Start(8080, 32);
  return 0;
}
/*==============================================================================
  Nouveau client a été accepté
==============================================================================*/
void onAccept(int idRequest, SOCKET i)
{
  //printf ("Socket %d accepté\n", i);
}
/*==============================================================================
  Des données arrivent. Renvoie la chaîne au client.
==============================================================================*/
void onData_Arrival(SOCKET i, char *request, short nbytes)
{
  int pF, n;
  struct stat buf;
  char header[255];
  time_t rawtime;
  char mot[255];
  unsigned char b=0, cpt=0;
  unsigned short lenURI=0;
  char *defindex="index.htm";
 //typedef struct {
  char *method       =NULL;
  char *URI          =NULL;
  char *protoversion =NULL;
 //} requete;

  puts(request);
  //cbx_log (request);
  // retrouve l' IP
   //inet_ntoa(CliAddr.sin_addr) <- le passer en char depuis servLib

  // parse requête
/*
  GET / HTTP/1.1
  Host: 127.0.0.1
  User-Agent: Mozilla/5.0 Firefox/1.5.0.8
  Accept: text/xml;q=0.5
  Accept-Language: fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3
  Accept-Encoding: gzip,deflate
  Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
  Keep-Alive: 300
  Connection: keep-alive
*/

  // parse la 1re ligne de la requête
  while (*request!=0)
  {
    if (request[0]==' ' || request[0]==0XA)
    {
      mot[b]=0; b=0;
      if      (cpt==0)  method=strdup(mot);
      else if (cpt==1) {URI=strdup(mot); lenURI=b; }
      else if (cpt==2) {protoversion =strdup(mot); break;}
      cpt++;
    }
    else mot[b++]=request[0];
    request++;
  }

  if (lenURI>255)
  {
    cbx_log ("%s|%s|414\n", method, URI);
    if (send(i, "HTTP/1.1 414\r\n\r\n<H2>Request-URL too long</H2>", 45, 0) == -1)
	perror("send()");
  }
  else if (method[0]=='G' && method[1]=='E' && method[2]=='T')
  {
//puts("ok, get");
    if (URI[lenURI]=='/') // c'est un dossier
    URI = strdup(defindex);
    pF = open(URI, O_RDONLY);

    // si ressource n' existe pas: 404
    if (!pF)
    {
      cbx_log ("%s|%s|404\n", method, URI);
      if (send(i, "HTTP/1.1 404\r\n\r\n<H2>Not found</H2>", 34, 0) == -1)
	perror("send()");
    }
    else
    {
      if ( fstat(pF, &buf)==-1) perror("fstat()");
      else
      {
        cbx_log ("%s|%s|200|%d\n", method, URI, buf.st_size);


        time ( &rawtime );
        n = sprintf( header,
		"HTTP/1.1 200 OK\n"
		"Date:%s"
		"Server:httpBX/1.1 (GNU/Linux)\n"
		"Last-Modified:%s"
		"Accept-Ranges:bytes\n"
		"Content-Length:%ld\n"
		"Content-Type:text/html; charset=iso-8859-1\r\n\r\n",
		ctime (&rawtime), ctime (&buf.st_ctime), buf.st_size);

        // envoie le header
        if (send(i, header, n, 0) == -1) perror("send()");

        // si CGI: pipe sur interpréteur
        // ouvre ressource en binaire et envoie. sendfile du kernel?
        if (sendfile(i, pF, 0, n) == -1) perror("sendfile");
      }
      close(pF);
    }
  }
  else
  {
    cbx_log ("%s|%s|405\n", method, URI);
    n = sprintf( header,
		"HTTP/1.1 405\n"
		"Server:httpBX/1.0 (GNU/Linux)\n"
		"Content-Length:53\n"
		"Content-Type:text/html; charset=iso-8859-1\r\n\r\n"
		"<H1>405 Method not allowed</H1>Only GET is supported.");
    if (send(i, header, n, 0) == -1) perror("send()");
  }
  // ferme connection
  closesocket(i);
  cbx_Serveur_Stop();
}
/*==============================================================================
  Un client quitte.
==============================================================================*/
void onClient_Left(SOCKET i)
{
  printf("Le socket %d vient de fermer sa connection\n", i);  
}
/*==============================================================================
  Survient en cas d' erreur inopinée
==============================================================================*/
void onError (SOCKET i, char *errmsg)
{
  fprintf(stderr, "Erreur sur le socket %d: %s\n", i, errmsg);
}